package main

import (
	"runtime"

	"github.com/go-gl/gl/v3.3-core/gl"
	"github.com/go-gl/glfw/v3.3/glfw"
)

func init() {
	// LockOSThread 将调用它的 goroutine 与其当前的操作系统线程绑定。
	// 该 goroutine 将始终在该线程中执行，
	// 并且没有其他 goroutine 会在该线程中执行，
	// 直到调用它的 goroutine 调用了与 LockOSThread 相同次数的 [UnlockOSThread] 为止。
	// 如果调用它的 goroutine 在没有解锁线程的情况下退出，
	// 那么该线程将被终止。
	//
	// 所有 init 函数都在启动线程上运行。从 init 函数中调用 LockOSThread
	// 将导致 main 函数在该线程上被调用。
	//
	// 在调用依赖于每线程状态的操作系统服务或非 Go 库函数之前，一个 goroutine 应该调用 LockOSThread。
	runtime.LockOSThread()
}

func main() {
	err := glfw.Init()
	if err != nil {
		panic(err)
	}
	defer glfw.Terminate()

	window, err := glfw.CreateWindow(640, 480, "Testing", nil, nil)
	if err != nil {
		panic(err)
	}

	window.MakeContextCurrent()

	// 必须在`MakeContextCurrent` 之后调用
	//
	// Init 函数通过从当前活动的 OpenGL 上下文中加载函数指针（针对每个 OpenGL 函数）来初始化 OpenGL 绑定。
	//
	// 它必须在存在活动 OpenGL 上下文的情况下调用，
	// 例如，总是在调用 window.MakeContextCurrent() 之后和调用本包导出的任何 OpenGL 函数之前调用。
	//
	// 在 Windows 上，Init 会加载特定于上下文的指针（因此，如果在 OpenGL 上下文之间切换，则必须重新初始化；
	// 尽管如果上下文属于相同的图形驱动程序/设备，在上下文切换后不再次调用 Init 也可能有效）。
	//
	// 在 macOS 和其他 POSIX 系统上，行为是不同的，但与 Windows 兼容的代码也与 macOS 和其他 POSIX 系统兼容。
	// 也就是说，总是在活动 OpenGL 上下文下调用 Init，并且在切换图形上下文后总是重新初始化。
	//
	// 有关 Init 的注意事项，您应该阅读 https://www.opengl.org/wiki/Load_OpenGL_Functions 页面上的“平台特定函数检索”部分。
	err = gl.Init()
	if err != nil {
		println("gl-init err:", err)
		return
	}

	processInput(window)
	window.SetFramebufferSizeCallback(func(w *glfw.Window, width, height int) {
		println("width:", width)
		println("height:", height)
		gl.Viewport(0, 0, int32(width)/2, int32(height)/2)
	})

	for !window.ShouldClose() {
		gl.ClearColor(0.2, 0.3, 0.3, 0.5)
		gl.Clear(gl.COLOR_BUFFER_BIT)
		// Do OpenGL stuff.
		window.SwapBuffers()
		glfw.PollEvents()
	}

	// runtime.UnlockOSThread()
}

func processInput(window *glfw.Window) {
	// window.GetKey(glfw.KeyEscape)
	window.SetKeyCallback(func(w *glfw.Window, key glfw.Key, scancode int, action glfw.Action, mods glfw.ModifierKey) {
		if key == glfw.KeyEscape && action == glfw.Press {
			println(">> escape press...", scancode)
			window.SetShouldClose(true)
		}
		if key == glfw.KeyA && action == glfw.Release {
			println(">> a press...", scancode)
		}
	})
}
